﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Reflection;
using System.Linq.Expressions;
using System.IO;

namespace CoolCode.Data.Linq
{
    [ProviderName("System.Data.SqlClient")]
    public partial class XDataContext : DataContext, IDataContext
    {
        protected bool WithLog = false;
        private static TextWriter sw;

        public string ConnectionString { get; set; }

        public XDataContext(string connectionString)
            : base(connectionString)
        {
            ConnectionString = connectionString;
            initialLog();
        }

        public XDataContext(string connectionString, MappingSource mappingSource)
            : base(connectionString, mappingSource)
        {
            ConnectionString = connectionString;
            initialLog();
        }

        public IRepository<T> CreateRepository<T>() where T : class
        {
            return new Repository<T>(this);
        }

        public IExecuteResult ExecuteStoredProcedure(object instance, MethodInfo method, params object[] parameters)
        {
            return this.ExecuteMethodCall(instance, method, parameters);
        }

        public IQueryable<T> ExecuteFunction<T>(object instance, MethodInfo method, params object[] parameters)
        {
            return this.CreateMethodCallQuery<T>(instance, method, parameters);
        }

        private void initialLog()
        {
            bool.TryParse(System.Configuration.ConfigurationManager.AppSettings["LogSQL"], out WithLog);
            if (WithLog)
            {
                if (sw == null)
                {
                    string path = Path.Combine(Directory.GetCurrentDirectory(), "logSQL.txt");
                    var fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                    sw = new StreamWriter(fs);
                }
                this.Log = sw;
            }
        }

        public override void SubmitChanges(ConflictMode failureMode)
        {
            base.SubmitChanges(failureMode);
            if (sw != null)
            {
                sw.Flush();
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (sw != null)
            {
                sw.Flush();
                sw.Dispose();
            }
        }

        ILoadOption IDataContext.LoadOptions { get { return new LoadOption(this); } }


        public class LoadOption : ILoadOption
        {
            private DataContext db;
            DataLoadOptions opt;

            public LoadOption(DataContext context)
            {
                db = context;
                opt = new DataLoadOptions();
            }

            #region ILoadOption Members

            public ILoadOption LoadWith<T>(Expression<Func<T, object>> property)
            {
                opt.LoadWith<T>(property);
                return this;
            }

            public void EndLoad()
            {
                db.LoadOptions = opt;
            }

            #endregion
        }
    }

}
